TOOL.Category    = "Conna's Tools"
TOOL.Name        = "#Sensor Tool"
TOOL.Command     = nil
TOOL.ConfigName  = ""

TOOL.ClientConVar["Model"] = "models/props_lab/jar01a.mdl"
TOOL.ClientConVar["Description"] = ""
TOOL.ClientConVar["Length"] = "100"
TOOL.ClientConVar["Key"] = "5"
TOOL.ClientConVar["Inversed"] = "0"
TOOL.ClientConVar["Once"] = "0"
TOOL.ClientConVar["Water"] = "0"

// Register

cleanup.Register("sensors")

// Console

CreateConVar("sbox_maxsensors", 10, FCVAR_NOTIFY)

// Client

if (CLIENT) then
	// Tool
	
	language.Add("Tool_sensor_name", "Sensor Tool")
	language.Add("Tool_sensor_desc", "Sensor which holds key when an object blocks it")
	language.Add("Tool_sensor_0", "Left click to spawn a Sensor")
	
	// Other
	
	language.Add("Undone_sensor", "Undone Sensor")
	language.Add("SBoxLimit_sensors", "You've hit the Sensors limit!")
	language.Add("Cleanup_sensors", "Sensors")
	language.Add("Cleaned_sensors", "Cleaned up all Sensors")
end

// Message

function TOOL:Message(Text)
	if SERVER then
		self:GetOwner():SendLua("GAMEMODE:AddNotify('"..Text.."', NOTIFY_GENERIC, 10)")
		self:GetOwner():SendLua("surface.PlaySound('ambient/water/drip"..math.random(1, 4)..".wav')")
	end
end

// Left click

function TOOL:LeftClick(Trace)
	if(CLIENT) then
		return true
	end
	
	// Locals
	
	local Player = self:GetOwner()

	local Key = self:GetClientNumber("Key")
	local Once = self:GetClientNumber("Once")
	local Water = self:GetClientNumber("Water")
	local Len = self:GetClientNumber("Length")
	local Inversed = self:GetClientNumber("Inversed")
	local Description = self:GetClientInfo("Description")
	local Model = self:GetClientInfo("Model")
	
	// Keep it nice and whole
	
	Len = math.floor(Len)
	
	if (Trace.Entity and Trace.Entity:IsValid() and Trace.Entity:GetClass() == "gmod_sensor") then
		local Entity = Trace.Entity
		
		// Merge
		
		local Table = {
			Key = Key,
			Once = Once,
			Water = Water,
			Inversed = Inversed,
			Len = Len,
			Description = Description
		}
		
		table.Merge(Entity:GetTable(), Table)
		
		// Other
		
		Entity:GetTable():SetEntityLength(Len)
		Entity:GetTable():SetEntityKey(Key)
		Entity:GetTable():SetEntityLabel(Description)
		
		self:Message("Properties changed for Sensor!")
		
		return true
	end
	
	local Ang = Trace.HitNormal:Angle()
	
	Ang.pitch = Ang.pitch + 90

	local Sensor = CreateSensor(Player, Ang, Trace.HitPos, Model, Once, Inversed, Water, Len, Key, Description)
	
	if not (Sensor) then return false end
	
	local Minimum = Sensor:OBBMins()
	
	Sensor:SetPos(Trace.HitPos - Trace.HitNormal * Minimum.z)
	
	undo.Create("sensor")
	
	if (Trace.Entity and not Trace.Entity:IsWorld()) then
		local Weld = constraint.Weld(Sensor, Trace.Entity, 0, Trace.PhysicsBone, 0, true, true)
		
		undo.AddEntity(Weld)
		
		Player:AddCleanup("sensors", Weld)
		
		Sensor:GetPhysicsObject():EnableCollisions(false)
	end
	
	undo.AddEntity(Sensor)
	undo.SetPlayer(Player)
	
	undo.Finish()
	
	Player:AddCount("sensors", Sensor)
	
	Player:AddCleanup("sensors", Sensor)
	
	self:Message("Sensor has been created!")
	
	return true, Sensor
end

// Make it

if (SERVER) then
	function CreateSensor(Player, Ang, Pos, Model, Once, Inversed, Water, Len, Key, Description, Nocollide, Vel, Avel, Frozen)
		if (!Player:CheckLimit("sensors")) then return false end
		
		local Sensor = ents.Create("gmod_sensor")
		
		util.PrecacheModel(Model)
		
		Sensor:SetModel(Model)
		Sensor:SetAngles(Ang)
		Sensor:SetPos(Pos)
		Sensor:Spawn()
		
		// Merge
		
		local Table = {
			Key = Key,
			Once, Once,
			Water = Water,
			Inversed = Inversed,
			Len = Len,
			Description = Description
		}
		
		table.Merge(Sensor:GetTable(), Table)
		
		// Set the entities owner
		
		Sensor:GetTable():SetPlayer(Player)
		
		// Other
		
		Sensor:GetTable():SetEntityLength(Len)
		Sensor:GetTable():SetEntityKey(Key)
		Sensor:GetTable():SetEntityLabel(Description)
		
		if Frozen then Sensor:GetPhysicsObject():EnableMotion(false) end

		if Nocollide then Sensor:GetPhysicsObject():EnableCollisions(false) end
		
		return Sensor
	end
	
	duplicator.RegisterEntityClass("gmod_sensor", CreateSensor, "Ang", "Pos", "Model", "Once", "Inversed", "Water", "Len", "Key", "Description", "Nocollide", "Vel", "Avel", "Frozen")
end

// Control panel

function TOOL.BuildCPanel(Panel)
	Panel:AddControl("Header", {Text = "#Tool_sensor_name", Description = "#Tool_sensor_desc"})

	local Models = {}
	
	Models["Jar"] = {}
	Models["Jar"]["sensor_Model"] = "models/props_lab/jar01a.mdl"
	
	Models["Doll"] = {}
	Models["Doll"]["sensor_Model"] = "models/props_lab/huladoll.mdl"
	
	Panel:AddControl("ComboBox", {Label = "Model", Options = Models, MenuButton = 0})
	
	Panel:AddControl("Slider", {Label = "Length", Type = "Integer", Min = 0, Max = 5000, Command = "sensor_Length"})
	
	Panel:AddControl("Numpad", {Label = "Key", Command = "sensor_Key", ButtonSize = 22})
	
	Panel:AddControl("CheckBox", {Label = "Inversed", Command = "sensor_Inversed"})
	
	Panel:AddControl("CheckBox", {Label = "Just press once don't continue to hold", Command = "sensor_Once"})
	
	Panel:AddControl("CheckBox", {Label = "Just detect water and nothing else", Command = "sensor_Water"})

	Panel:AddControl("TextBox", {Label = "Description", MaxLength = "100", Command = "sensor_Description"})
end

// Ghost

function TOOL:UpdateGhostSensor(Entity, Player)
	if (!Entity) then return end
	
	if (!Entity:IsValid()) then return end

	local TR = utilx.GetPlayerTrace(Player, Player:GetCursorAimVector())
	
	local Trace = util.TraceLine(TR)
	
	if (!Trace.Hit) then return end
	
	if (Trace.Entity && Trace.Entity:GetClass() == "gmod_sensor" || Trace.Entity:IsPlayer()) then
		Entity:SetNoDraw(true)
		
		return
	end
	
	local Ang = Trace.HitNormal:Angle()
	
	Ang.pitch = Ang.pitch + 90
	
	local Minimum = Entity:OBBMins()
	
	Entity:SetPos(Trace.HitPos - Trace.HitNormal * Minimum.z)
	
	Entity:SetAngles(Ang)
	
	Entity:SetNoDraw(false)
end

// Think

function TOOL:Think()
	if not (self.Precached) then
		util.PrecacheModel("models/props_lab/jar01a.mdl")
		
		self.Precached = true
	end
	
	if (self:GetOwner() and self:GetOwner():IsPlayer()) then
		if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != self:GetClientInfo("Model")) then
			self:MakeGhostEntity(self:GetClientInfo("Model"), Vector(0, 0, 0), Angle(0, 0, 0) )
		end
		
		self:UpdateGhostSensor(self.GhostEntity, self:GetOwner())
	end
end